﻿using System;

namespace CommonEngine.Helper
{
    /// <summary>
    /// 随机数助手
    /// </summary>
    public sealed class RandomHelper
    {
        /// <summary>
        /// 字符集合（去掉 0oO 这几个容易混淆的字符）
        /// </summary>
        private const string CharSet = "123456789abcdefghijklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ~!@#$%^&*()_+|";

        private static readonly Random Random = new Random();

        #region Next

        /// <summary>
        /// 返回非负随机数
        /// </summary>
        /// <returns> 大于等于零且小于 System.Int32.MaxValue 的 32 位带符号整数 </returns>
        public static int Next()
        {
            return Random.Next();
        }

        /// <summary>
        /// 返回一个指定范围内的随机数
        /// </summary>
        /// <param name="maxValue"> 要生成的随机数的上限（随机数不能取该上限值）。maxValue 必须大于或等于零 </param>
        /// <returns>
        /// 大于等于零且小于 maxValue 的 32 位带符号整数，即：返回值的范围通常包括零但不包括 maxValue。 不过，如果 maxValue 等于零，则返回 maxValue。
        /// </returns>
        public static int Next(int maxValue)
        {
            return Random.Next(maxValue);
        }

        /// <summary>
        /// 返回一个指定范围内的随机数
        /// </summary>
        /// <param name="minValue"> 返回的随机数的下界（随机数可取该下界值） </param>
        /// <param name="maxValue"> 返回的随机数的上界（随机数不能取该上界值）。 maxValue 必须大于或等于 minValue</param>
        /// <returns>
        /// 一个大于等于 minValue 且小于 maxValue 的 32 位带符号整数，即：返回的值范围包括 minValue 但不包括 maxValue。
        /// 如果 minValue 等于 maxValue，则返回 minValue。
        /// </returns>
        public static int Next(int minValue, int maxValue)
        {
            return Random.Next(minValue, maxValue);
        }

        #endregion Next

        /// <summary>
        /// 返回一个介于 0.0 和 1.0 之间的随机数
        /// </summary>
        /// <returns> 大于等于 0.0 并且小于 1.0 的双精度浮点数 </returns>
        public static double NextDouble()
        {
            return Random.NextDouble();
        }

        /// <summary>
        /// 返回一个随机字符串
        /// </summary>
        /// <param name="length"> 字符串长度 </param>
        /// <returns></returns>
        public static string NextString(int length)
        {
            var arr = new char[length];

            for (var i = 0; i < length; i++)
            {
                var index = Random.Next(CharSet.Length);
                arr[i] = CharSet[index];
            }

            return string.Join("", arr);
        }

        /// <summary>
        /// 生成一个0.0到1.0的随机小数
        /// </summary>
        public double GetRandomDouble()
        {
            return Random.NextDouble();
        }

        /// <summary>
        /// 对一个数组进行随机排序
        /// </summary>
        /// <typeparam name="T">数组的类型</typeparam>
        /// <param name="arr">需要随机排序的数组</param>
        public void GetRandomArray<T>(T[] arr)
        {
            //对数组进行随机排序的算法:随机选择两个位置，将两个位置上的值交换

            //交换的次数,这里使用数组的长度作为交换次数
            int count = arr.Length;

            //开始交换
            for (int i = 0; i < count; i++)
            {
                //生成两个随机数位置
                int randomNum1 = Next(0, arr.Length);
                int randomNum2 = Next(0, arr.Length);

                //定义临时变量
                T temp;

                //交换两个随机数位置的值
                temp = arr[randomNum1];
                arr[randomNum1] = arr[randomNum2];
                arr[randomNum2] = temp;
            }
        }

        private static int rep = 0;
        //方法二：随机生成不重复数字字符串 
        public static string GenerateCheckCodeNum(int codeCount)
        {
            if (rep > 10000)
                rep = 0;

            string str = string.Empty;
            long num2 = DateTime.Now.Ticks + rep;
            rep++;
            Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
            for (int i = 0; i < codeCount; i++)
            {
                int num = random.Next();
                str = str + ((char)(0x30 + ((ushort)(num % 10)))).ToString();
            }
            return str;
        }

        //方法二：随机生成字符串（数字和字母混和）
        public static string GenerateCheckCode(int codeCount)
        {
            if (rep > 10000)
                rep = 0;

            string str = string.Empty;
            long num2 = DateTime.Now.Ticks + rep;
            rep++;
            Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
            for (int i = 0; i < codeCount; i++)
            {
                char ch;
                int num = random.Next();
                if ((num % 2) == 0)
                {
                    ch = (char)(0x30 + ((ushort)(num % 10)));
                }
                else
                {
                    ch = (char)(0x41 + ((ushort)(num % 0x1a)));
                }
                str = str + ch.ToString();
            }
            return str;
        }

        /// <summary>
        /// 从字符串里随机得到，规定个数的字符串.
        /// </summary>
        public static string GetRandomCode(string allChar, int CodeCount)
        {
            //string allChar = "1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,i,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"; 
            string[] allCharArray = allChar.Split(',');
            string RandomCode = "";
            int temp = -1;
            Random rand = new Random();
            for (int i = 0; i < CodeCount; i++)
            {
                if (temp != -1)
                {
                    rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
                }

                int t = rand.Next(allCharArray.Length - 1);

                while (temp == t)
                {
                    t = rand.Next(allCharArray.Length - 1);
                }

                temp = t;
                RandomCode += allCharArray[t];
            }
            return RandomCode;
        }
    }
}
